package com.maodou.core.datastore.db

import com.maodou.core.datastore.db.dao.AccountDao
import com.maodou.core.datastore.db.table.AccountEntry
import com.maodou.core.manager.GlobalStateManager
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * 用户感知的账号本地数据库 Store
 * - 所有操作都自动限定到“当前登录用户”作用域
 * - 增删改查、分页、分类筛选、关键字模糊搜索、前缀联想
 */
class AccountStore(
    private val dao: AccountDao,
    private val globalStateManager: GlobalStateManager,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {

    // =============== 公共模型 ===============
    data class PagedResult<T>(
        val items: List<T>,
        val page: Int,
        val pageSize: Int,
        val total: Int,
        val hasMore: Boolean
    )

    // =============== 内部工具 ===============
    private fun requireCurrentUserId(): String =
        globalStateManager.getCurrentUserId()
            ?: throw IllegalStateException("User not logged in, cannot access account store")

    private fun composeKey(userId: String, accountID: String): String = "u:${userId}|a:${accountID}"

    private fun offsetOf(page: Int, pageSize: Int): Int {
        val p = if (page < 1) 1 else page
        val ps = if (pageSize < 1) 20 else pageSize
        return (p - 1) * ps
    }

    private val AUTO_TAGS: Set<String> = setOf("2FA", "邮箱", "邮箱密码", "手机号", "Cookie", "认证令牌", "密码", "国家/地区", "代理")

    private fun splitTags(raw: String?): Set<String> {
        if (raw.isNullOrBlank()) return emptySet()
        return raw.split(',', '，', '|', ' ').map { it.trim() }.filter { it.isNotEmpty() }.toSet()
    }

    /**
     * 按字段值生成“自动标签”，并与用户已有标签合并：
     * - 移除旧的“自动标签”，以当前字段重新计算（保持同步）
     * - 保留用户手动添加的其他标签
     */
    private fun mergeAutoTags(entry: AccountEntry): String? {
        val manual = splitTags(entry.tags).filterNot { it in AUTO_TAGS }.toMutableSet()
        val auto = mutableSetOf<String>()
        if (!entry.twoFa.isNullOrBlank()) auto += "2FA"
        if (!entry.email.isNullOrBlank()) auto += "邮箱"
        if (!entry.emailPassword.isNullOrBlank()) auto += "邮箱密码"
        if (!entry.phone.isNullOrBlank()) auto += "手机号"
        if (!entry.cookie.isNullOrBlank()) auto += "Cookie"
        if (!entry.authCode.isNullOrBlank()) auto += "认证令牌"
        if (!entry.password.isNullOrBlank()) auto += "密码"
        if (!entry.ipCountry.isNullOrBlank()) auto += "国家/地区"
        if (!entry.proxyChannel.isNullOrBlank()) auto += "代理"
        val result = (manual + auto).toSortedSet() // 排序保证稳定性
        return if (result.isEmpty()) null else result.joinToString(",")
    }

    // =============== 写入 ===============
    /** 保存/更新单个账号（按 userId + accountID 唯一）。会覆盖入参中的 userId 与 key，保证安全。 */
    suspend fun upsert(entry: AccountEntry): Long = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val now = System.currentTimeMillis()
        val withTags = entry.copy(tags = mergeAutoTags(entry))
        dao.upsert(
            withTags.copy(
                userId = userId,
                key = composeKey(userId, withTags.accountID),
                // Room 中 updatedAt 按我们时间戳刷新，避免排序为 null
                updatedAt = now
            )
        )
    }

    /** 批量保存/更新账号。会对每条记录的 userId 与 key 进行强制修正。 */
    suspend fun upsertAll(entries: List<AccountEntry>): List<Long> = withContext(ioDispatcher) {
        if (entries.isEmpty()) return@withContext emptyList<Long>()
        val userId = requireCurrentUserId()
        val now = System.currentTimeMillis()
        val fixed = entries.map { e ->
            val withTags = e.copy(tags = mergeAutoTags(e))
            withTags.copy(
                userId = userId,
                key = composeKey(userId, withTags.accountID),
                updatedAt = now
            )
        }
        dao.upsertAll(fixed)
    }

    // =============== 删除 ===============
    suspend fun deleteByAccountId(accountID: String): Int = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        dao.delete(userId, accountID)
    }

    suspend fun clearCurrentUserData(): Int = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        dao.clearAccountData(userId)
    }

    // =============== 查询 ===============
    suspend fun findByAccountId(accountID: String): AccountEntry? = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        dao.findByAccountId(userId, accountID)
    }

    /** 简单分页（全部类型） */
    suspend fun page(page: Int, pageSize: Int): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val offset = offsetOf(page, pageSize)
        val items = dao.pageByUser(userId, pageSize, offset)
        val total = dao.countByUser(userId)
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    /** 按单一类型分页 */
    suspend fun pageByType(type: String, page: Int, pageSize: Int): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val offset = offsetOf(page, pageSize)
        val items = dao.pageByUserAndType(userId, type, pageSize, offset)
        val total = dao.countByUserAndTypes(userId, listOf(type))
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    /** 按多个类型分页 */
    suspend fun pageByTypes(types: List<String>, page: Int, pageSize: Int): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val offset = offsetOf(page, pageSize)
        val items = dao.pageByUserAndTypes(userId, types, pageSize, offset)
        val total = dao.countByUserAndTypes(userId, types)
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    /** 模糊搜索（所有可检索字段） */
    suspend fun search(keyword: String, page: Int, pageSize: Int): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val kw = "%$keyword%"
        val offset = offsetOf(page, pageSize)
        val items = dao.search(userId, kw, pageSize, offset)
        val total = dao.countBySearch(userId, kw)
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    /** 模糊搜索 + 类型过滤 */
    suspend fun searchByTypes(types: List<String>, keyword: String, page: Int, pageSize: Int): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val kw = "%$keyword%"
        val offset = offsetOf(page, pageSize)
        val items = dao.searchByTypes(userId, types, kw, pageSize, offset)
        val total = dao.countBySearchAndTypes(userId, types, kw)
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    /** 前缀联想（账号ID/昵称） */
    suspend fun prefixSuggest(prefix: String, limit: Int = 20): List<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val list = dao.getByPrefix(userId, prefix)
        if (list.size <= limit) list else list.take(limit)
    }

    /** 多条件筛选分页查询 */
    suspend fun pageByFilter(
        platforms: Set<String>?,
        statuses: Set<String>?,
        tags: Set<String>?,
        page: Int,
        type: String,
        pageSize: Int
    ): PagedResult<AccountEntry> = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        val offset = offsetOf(page, pageSize)

        val platformList = if (platforms.isNullOrEmpty()) null else platforms.toList()
        val statusList = if (statuses.isNullOrEmpty()) null else statuses.map { 
            when (it) {
                "待检测" -> 1
                "存活中" -> 2
                "被封禁" -> 3
                else -> -1
            }
        }.filter { it >= 0 }
        // 对于标签，我们只取第一个标签进行匹配，后续可以改进为支持多标签匹配
        // val tagsString = if (tags.isNullOrEmpty()) null else tags.joinToString(",")
        val tagsString = if (tags.isNullOrEmpty()) null else tags.first()

        val finalStatusList = if (statusList.isNullOrEmpty()) null else statusList
        
        val items = dao.pageByFilter(
            userId = userId,
            platforms = platformList,
            platformsEmpty = if (platformList.isNullOrEmpty()) 1 else 0,
            statuses = finalStatusList,
            statusesEmpty = if (finalStatusList.isNullOrEmpty()) 1 else 0,
            tags = tagsString,
            type = type,
            limit = pageSize,
            offset = offset
        )
        
        val total = dao.countByFilter(
            userId = userId,
            type = type,
            platforms = platformList,
            platformsEmpty = if (platformList.isNullOrEmpty()) 1 else 0,
            statuses = finalStatusList,
            statusesEmpty = if (finalStatusList.isNullOrEmpty()) 1 else 0,
            tags = tagsString
        )
        
        PagedResult(
            items = items,
            page = if (page < 1) 1 else page,
            pageSize = if (pageSize < 1) 20 else pageSize,
            total = total,
            hasMore = offset + items.size < total
        )
    }

    // =============== 状态更新 ===============
    suspend fun setSelected(accountID: String, selected: Boolean): Int = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        dao.updateSelect(userId, accountID, selected)
    }

    /**
     * 更新账号在线状态
     * @param status 1=待检测  2=存活中 3=被封禁
     */
    suspend fun updateStatus(accountID: String, status: Int, lastCheck: Long? = System.currentTimeMillis()): Int = withContext(ioDispatcher) {
        val userId = requireCurrentUserId()
        dao.updateStatus(userId, accountID, status, lastCheck)
    }

    /**
     * 批量删除多个账号（自动限定到当前登录用户）
     */
    suspend fun deleteMany(accountIDs: List<String>): Int = withContext(ioDispatcher) {
        if (accountIDs.isEmpty()) return@withContext 0
        val userId = requireCurrentUserId()
        dao.deleteMany(userId, accountIDs)
    }
}